/**
 *    title:  network.c
 *    author:  sleeeeeping
 *    created:  2024-08-16 09:23:21
**/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "network.h"

NetWork *createNetWork(int type, const char *ip, unsigned short port, bool isServer) {
    NetWork *nw = malloc(sizeof(NetWork));
    if (nw == NULL) {
        perror("malloc");
        return NULL;
    }
    nw->sockfd = socket(AF_INET, type, 0);
    if (nw->sockfd < 0) {
        perror("socket");
        free(nw);
        return NULL;
    }
	nw->addr.sin_family = AF_INET;
	nw->addr.sin_port = htons(port);
	nw->addr.sin_addr.s_addr = inet_addr(ip);
	nw->addrlen = sizeof(nw->addr);
    if (isServer) {
        if (bind(nw->sockfd, (struct sockaddr *)&nw->addr, nw->addrlen)) {
            perror("bind");
            free(nw);
            return NULL;
        }
        if (SOCK_STREAM == type && listen(nw->sockfd, 6)) {
            perror("listen");
            free(nw);
            return NULL;
        }
    } else if (SOCK_STREAM == type) {
        if (connect(nw->sockfd, (struct sockaddr *)&nw->addr, nw->addrlen)) {
            perror("connect");
            free(nw);
            return NULL;
        }
    }
    nw->type = type;
    nw->isServer = isServer;
    return nw;
}

NetWork *acceptNetWork(NetWork *nw) {
    if (SOCK_STREAM != nw->type || !nw->isServer) {
        printf("nw arg not SOCK_STREAM or SERVER\n");
        return NULL;
    }    
    NetWork *cnw = malloc(sizeof(NetWork));
    if (cnw == NULL) {
        perror("malloc");
        return NULL;
    }
    cnw->addrlen = sizeof(cnw->addr);
    cnw->type = SOCK_STREAM;
    cnw->isServer = false;
    cnw->sockfd = accept(nw->sockfd, (struct sockaddr *)&cnw->addr, &cnw->addrlen);
    if (0 > cnw->sockfd) {
        perror("accept");
        free(cnw);
        return NULL;
    }
    return cnw;
}

int sendNetWork(NetWork *nw, const void *buf, size_t len) {
    if (SOCK_STREAM == nw->type) {
        return send(nw->sockfd, buf, len, 0);
    } else {
        return sendto(nw->sockfd, buf, len, 0, (struct sockaddr *)&nw->addr, nw->addrlen);
    }
}

int recvNetWork(NetWork *nw, void *buf, size_t len) {
    if (SOCK_STREAM == nw->type) {
        return recv(nw->sockfd, buf, len, 0);
    } else {
        return recvfrom(nw->sockfd, buf, len, 0, (struct sockaddr *)&nw->addr, &nw->addrlen);
    }
}

int closeNetWork(NetWork *nw) {
    int ret = close(nw->sockfd);
    free(nw);
    return ret;
}